/*
 * PhotonRTOS础光实时操作系统 -- 精确计数头文件
 *
 * Copyright (C) 2022, 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Baoyou Xie <xiebaoyou@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef PHOTON_ACCURATE_COUNTER_H
#define PHOTON_ACCURATE_COUNTER_H

#include <photon/compiler.h>

struct accurate_counter {
	intptr_t counter;
};

#include <asm/accurate_counter.h>

#define ACCURATE_COUNTER_INIT(i)	{ (i) }

static inline intptr_t accurate_read(struct accurate_counter *l)
{
	return ACCESS_ONCE(l->counter);
}

static inline void accurate_set(struct accurate_counter *l, intptr_t i)
{
	l->counter = i;
}

static inline intptr_t accurate_inc(struct accurate_counter *l)
{
	return arch_accurate_add(1UL, l);
}

static inline intptr_t accurate_dec(struct accurate_counter *l)
{
	return arch_accurate_sub(1UL, l);
}

static inline intptr_t accurate_add(intptr_t i, struct accurate_counter *l)
{
	return arch_accurate_add(i, l);
}

static inline intptr_t accurate_sub(intptr_t i, struct accurate_counter *l)
{
	return arch_accurate_sub(i, l);
}

static inline intptr_t accurate_sub_and_test_zero(intptr_t i,
		struct accurate_counter *l)
{
	return arch_accurate_sub(i, l) == 0;
}

static inline intptr_t accurate_dec_and_test_zero(struct accurate_counter *l)
{
	return arch_accurate_sub(1UL, l) == 0;
}

static inline intptr_t accurate_inc_and_test_zero(struct accurate_counter *l)
{
	return arch_accurate_add(1UL, l) == 0;
}

static inline intptr_t accurate_add_test_negative(intptr_t i,
		struct accurate_counter *l)
{
	return arch_accurate_add(i, l) < 0;
}

static inline intptr_t accurate_add_ifneq(struct accurate_counter *l,
		intptr_t a, intptr_t u)
{
	intptr_t c, old;

	c = accurate_read(l);
	while (c != u && (old = arch_accurate_cmpxchg(l, c, c + a)) != c)
		c = old;

	return c != u;
}

#define accurate_inc_not_zero(l)	accurate_add_ifneq((l), 1LL, 0LL)

#define accurate_cmpxchg(l, old, new)						\
	(arch_accurate_cmpxchg((struct accurate_counter *)(l), (old), (new)))

#define xchg_ptr(ptr, x)							\
({										\
	__typeof__(*(ptr)) __ret;						\
	__ret = (__typeof__(*(ptr)))						\
		arch_accurate_xchg((uintptr_t)(x), (ptr), sizeof(*(ptr)));	\
	__ret;									\
})

#define accurate_xchg(v, new) (xchg_ptr(&((v)->counter), new))

#endif /* PHOTON_ACCURATE_COUNTER_H */
